# ~*~ coding: utf-8 ~*~
from flask import request, views, render_template, jsonify
from flask_login import current_user

from apps.common.utils import fill_date_to_timestamp, timestamp_obj_to_str, list2dict
from apps.common.mixin import CompatibleWithSelect2Mixin
from apps.common import response
from apps.extensions import db
from apps.assets.models import Asset
from apps.perms.mixin import PermissionRequiredMixin, LoginRequiredMixin
from ...models import InventoryGroup, InventoryGroupHost, InventoryHostVariable
from ...forms import InventoryGroupForm, InventoryHostVariableForm


__all__ = [
    'InventoryGroupListAPI', 'InventoryGroupListView', 'InventoryGroupCreateView',
    'InventoryGroupUpdateView', 'InventoryGroupDeleteView',
    'InventoryHostVariableListAPI', 'InventoryHostVariableListView', 'InventoryHostVariableCreateView',
    'InventoryHostVariableUpdateView', 'InventoryHostVariableDeleteView',
]


# InventoryGroup

class InventoryGroupListAPI(CompatibleWithSelect2Mixin, PermissionRequiredMixin, LoginRequiredMixin, views.MethodView):
    permission_required = 'tasks-group-list'

    def get(self):
        create_time = request.args.get('create_time')
        start_time = end_time = None
        if create_time:
            start_time = fill_date_to_timestamp('start', create_time.split('~')[0])
            end_time = fill_date_to_timestamp('end', create_time.split('~')[1])

        filter_conditions = {
            'and': [
                ('create_time', 'gte', start_time),
                ('create_time', 'lte', end_time),
            ],
            'or': [
                # ('name', 'like', request.args.get('search')),
            ],
        }

        # 排序
        sort = request.args.get('sort') or 'create_time'
        order = request.args.get('order') or 'desc'
        order_by_list = [(sort, order), ]

        # 分页
        offset = request.args.get('offset') or 0
        limit = request.args.get('limit') or 12

        # Compatible with select2
        if request.values.get('type') == 'select2':
            filter_conditions, order_by_list, offset, limit = self.select2_queryset()

        groups, count = InventoryGroup.get_queryset(filter_conditions=filter_conditions,
                                                    order_by_list=order_by_list,
                                                    offset=offset, limit=limit)

        # 关联查询所属主机信息
        group_ids = [g.id for g in groups]
        host_dict = db.session.query(InventoryGroupHost.group_id, Asset.hostname).\
            join(Asset, InventoryGroupHost.asset_id == Asset.id).\
            filter(InventoryGroupHost.group_id.in_(group_ids)).\
            all()
        host_dict = list2dict(host_dict)

        results = list()
        for group in groups:
            results.append({
                'id': group.id,
                'name': group.name,
                'vars': ','.join(['{}={}'.format(k, str(v)) for k, v in group.vars.items()]),
                'hosts': host_dict.get(group.id),
                'memo': group.memo,
                'create_by': group.create_by,
                'create_time': timestamp_obj_to_str(group.create_time),
            })

        resp = {
            "data": {
                "rows": results,
                "total": count
            }
        }
        return jsonify(resp)


class InventoryGroupListView(PermissionRequiredMixin, LoginRequiredMixin, views.MethodView):
    permission_required = 'tasks-group-list'

    def get(self):
        return render_template('tasks/realtime/group_list.html')


class InventoryGroupUpdateView(PermissionRequiredMixin, LoginRequiredMixin, views.MethodView):
    permission_required = 'tasks-group-update'

    def get(self, pk):
        instance = db.session.query(InventoryGroup).get(pk)
        asset_ids = db.session.query(InventoryGroupHost.asset_id).\
            filter(InventoryGroupHost.group_id == instance.id).\
            all()
        asset_ids = ','.join(list(zip(*asset_ids))[0])

        content = {
            'id': instance.id,
            'name': instance.name,
            'vars': instance.vars.items(),
            'hosts': asset_ids,
            'memo': instance.memo,
            'create_by': instance.create_by,
            'create_time': timestamp_obj_to_str(instance.create_time),
        }
        return render_template('tasks/realtime/group_update.html', **content)

    def post(self, pk):
        form = InventoryGroupForm(request.values)
        instance = db.session.query(InventoryGroup).get(pk)
        if form.validate():
            _clean_data = form.data
            if instance.name != _clean_data.get('name'):
                if db.session.query(InventoryGroup).filter_by(name=_clean_data.get('name')).count():
                    return response.params_error({
                        'field': 'name',
                        'message': '主机组名称不能重复'
                    })

            asset_ids = _clean_data.pop('asset_ids')
            group = instance.update(**_clean_data, commit=False)
            db.session.flush()
            # 先删除
            db.session.query(InventoryGroupHost).filter(InventoryGroupHost.group_id == group.id).delete()
            # 后增加
            assets = []
            for asset_id in asset_ids.split(','):
                assets.append(InventoryGroupHost(group_id=group.id, asset_id=asset_id))
            db.session.bulk_save_objects(assets)
            db.session.commit()
            return response.success()
        else:
            return response.params_error(form.get_error())


class InventoryGroupCreateView(PermissionRequiredMixin, LoginRequiredMixin, views.MethodView):
    permission_required = 'tasks-group-create'

    def get(self):
        return render_template('tasks/realtime/group_create.html')

    def post(self):
        form = InventoryGroupForm(request.values)
        if form.validate():
            _clean_data = form.data
            if db.session.query(InventoryGroup).filter_by(name=_clean_data.get('name')).count():
                return response.params_error({
                    'field': 'name',
                    'message': '主机组名称不能重复'
                })

            asset_ids = _clean_data.pop('asset_ids')
            _clean_data['create_by'] = current_user.name
            group = InventoryGroup.create(**_clean_data, commit=False)
            db.session.flush()

            assets = []
            for asset_id in asset_ids.split(','):
                assets.append(InventoryGroupHost(group_id=group.id, asset_id=asset_id))
            db.session.bulk_save_objects(assets)
            db.session.commit()

            return response.success()
        else:
            return response.params_error(form.get_error())


class InventoryGroupDeleteView(PermissionRequiredMixin, LoginRequiredMixin, views.MethodView):
    permission_required = 'tasks-group-delete'

    def post(self, pk):
        instance = db.session.query(InventoryGroup).get(pk)
        instance.delete(commit=False)
        db.session.query(InventoryGroupHost).\
            filter(InventoryGroupHost.group_id == instance.id).\
            delete(synchronize_session=False)
        db.session.commit()
        return response.success()


# InventoryHostVariable


class InventoryHostVariableListAPI(CompatibleWithSelect2Mixin, PermissionRequiredMixin, LoginRequiredMixin, views.MethodView):
    permission_required = 'tasks-host-list'

    def get(self):
        create_time = request.args.get('create_time')
        start_time = end_time = None
        if create_time:
            start_time = fill_date_to_timestamp('start', create_time.split('~')[0])
            end_time = fill_date_to_timestamp('end', create_time.split('~')[1])

        filter_conditions = {
            'and': [
                ('create_time', 'gte', start_time),
                ('create_time', 'lte', end_time),
            ],
            'or': [
                # ('name', 'like', request.args.get('search')),
            ],
        }

        # 排序
        sort = request.args.get('sort') or 'create_time'
        order = request.args.get('order') or 'desc'
        order_by_list = [(sort, order), ]

        # 分页
        offset = request.args.get('offset') or 0
        limit = request.args.get('limit') or 12

        # Compatible with select2
        if request.values.get('type') == 'select2':
            filter_conditions, order_by_list, offset, limit = self.select2_queryset()

        hosts, count = InventoryHostVariable.get_queryset(filter_conditions=filter_conditions,
                                                          order_by_list=order_by_list,
                                                          offset=offset, limit=limit)
        host_ids = [h.id for h in hosts]
        asset_dict = db.session.query(InventoryHostVariable.id, Asset.hostname).\
            join(Asset, InventoryHostVariable.asset_id == Asset.id).\
            filter(InventoryHostVariable.id.in_(host_ids)).\
            all()
        asset_dict = list2dict(asset_dict)

        results = list()
        for host in hosts:
            results.append({
                'id': host.id,
                'asset': asset_dict.get(host.id),
                'vars': ','.join(['{}={}'.format(k, str(v)) for k, v in host.vars.items()]),
                'create_by': host.create_by,
                'create_time': timestamp_obj_to_str(host.create_time),
            })

        resp = {
            "data": {
                "rows": results,
                "total": count
            }
        }
        return jsonify(resp)


class InventoryHostVariableListView(PermissionRequiredMixin, LoginRequiredMixin, views.MethodView):
    permission_required = 'tasks-host-list'

    def get(self):
        return render_template('tasks/realtime/host_list.html')


class InventoryHostVariableUpdateView(PermissionRequiredMixin, LoginRequiredMixin, views.MethodView):
    permission_required = 'tasks-host-update'

    def get(self, pk):
        instance = db.session.query(InventoryHostVariable).get(pk)
        content = {
            'id': instance.id,
            'host': instance.asset_id,
            'vars': instance.vars.items(),
        }
        return render_template('tasks/realtime/host_update.html', **content)

    def post(self, pk):
        form = InventoryHostVariableForm(request.values)
        instance = db.session.query(InventoryHostVariable).get(pk)
        if form.validate():
            _clean_data = form.data
            if instance.asset_id != _clean_data.get('asset_id'):
                if db.session.query(InventoryHostVariable).filter_by(asset_id=_clean_data.get('asset_id')).count():
                    return response.params_error({
                        'field': 'name',
                        'message': '主机名称不能重复'
                    })

            instance.update(**_clean_data)
            return response.success()
        else:
            return response.params_error(form.get_error())


class InventoryHostVariableCreateView(PermissionRequiredMixin, LoginRequiredMixin, views.MethodView):
    permission_required = 'tasks-host-create'

    def get(self):
        return render_template('tasks/realtime/host_create.html')

    def post(self):
        form = InventoryHostVariableForm(request.values)
        if form.validate():
            _clean_data = form.data
            if db.session.query(InventoryHostVariable).filter_by(asset_id=_clean_data.get('asset_id')).count():
                return response.params_error({
                    'field': 'asset_id',
                    'message': '主机名称不能重复'
                })

            _clean_data['create_by'] = current_user.name
            InventoryHostVariable.create(**_clean_data)
            return response.success()
        else:
            return response.params_error(form.get_error())


class InventoryHostVariableDeleteView(PermissionRequiredMixin, LoginRequiredMixin, views.MethodView):
    permission_required = 'tasks-host-delete'

    def post(self, pk):
        instance = db.session.query(InventoryHostVariable).get(pk)
        instance.delete()
        return response.success()
